﻿Imports System
Imports System.CodeDom
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Diagnostics
Imports System.Drawing.Design
Imports System.Reflection
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.ComponentModel.Design
    Friend Class ActivityBindPropertyDescriptor
        Inherits DynamicPropertyDescriptor
        ' Methods
        Friend Sub New(ByVal serviceProvider As IServiceProvider, ByVal realPropertyDescriptor As PropertyDescriptor, ByVal propertyOwner As Object)
            MyBase.New(serviceProvider, realPropertyDescriptor)
            Me.propertyOwner = propertyOwner
        End Sub

        Friend Shared Function CreateField(ByVal context As ITypeDescriptorContext, ByVal activityBind As ActivityBind, ByVal throwOnError As Boolean) As Boolean
            If Not String.IsNullOrEmpty(activityBind.Path) Then
                Dim toType As Type = PropertyDescriptorUtils.GetBaseType(context.PropertyDescriptor, context.Instance, context)
                Dim component As Activity = [TryCast](PropertyDescriptorUtils.GetComponent(context),Activity)
                If ((Not component Is Nothing) AndAlso (Not toType Is Nothing)) Then
                    component = Helpers.ParseActivityForBind(component, activityBind.Name)
                    If (component Is Helpers.GetRootActivity(component)) Then
                        Dim ignoreCase As Boolean = (CompilerHelpers.GetSupportedLanguage(context) = SupportedLanguages.VB)
                        Dim dataSourceClass As Type = Helpers.GetDataSourceClass(component, context)
                        If (Not dataSourceClass Is Nothing) Then
                            Dim path As String = activityBind.Path
                            Dim length As Integer = path.IndexOfAny(New Char() { "."c, "/"c, "["c })
                            If (length <> -1) Then
                                path = path.Substring(0, length)
                            End If
                            Dim info As MemberInfo = ActivityBindPropertyDescriptor.FindMatchingMember(path, dataSourceClass, ignoreCase)
                            If (Not info Is Nothing) Then
                                Dim fromType As Type = Nothing
                                Dim isPrivate As Boolean = False
                                If TypeOf info Is FieldInfo Then
                                    isPrivate = DirectCast(info, FieldInfo).IsPrivate
                                    fromType = DirectCast(info, FieldInfo).FieldType
                                ElseIf TypeOf info Is PropertyInfo Then
                                    Dim getMethod As MethodInfo = DirectCast(info, PropertyInfo).GetGetMethod
                                    Dim setMethod As MethodInfo = DirectCast(info, PropertyInfo).GetSetMethod
                                    isPrivate = (((Not getMethod Is Nothing) AndAlso getMethod.IsPrivate) OrElse ((Not setMethod Is Nothing) AndAlso setMethod.IsPrivate))
                                ElseIf TypeOf info Is MethodInfo Then
                                    isPrivate = DirectCast(info, MethodInfo).IsPrivate
                                End If
                                If (length <> -1) Then
                                    Dim walker As New PathWalker
                                    Dim finalEventArgs As PathMemberInfoEventArgs = Nothing
                                    walker.MemberFound = DirectCast(Delegate.Combine(walker.MemberFound, Function (ByVal sender As Object, ByVal eventArgs As PathMemberInfoEventArgs) 
                                        finalEventArgs = eventArgs
                                    End Function), EventHandler([Of] PathMemberInfoEventArgs))
                                    If Not walker.TryWalkPropertyPath(dataSourceClass, activityBind.Path) Then
                                        If throwOnError Then
                                            Throw New InvalidOperationException(SR.GetString("Error_MemberWithSameNameExists", New Object() { activityBind.Path, dataSourceClass.FullName }))
                                        End If
                                        Return False
                                    End If
                                    fromType = BindHelpers.GetMemberType(finalEventArgs.MemberInfo)
                                End If
                                If (((info.DeclaringType Is dataSourceClass) OrElse Not isPrivate) AndAlso (TypeOf info Is FieldInfo AndAlso TypeProvider.IsAssignable(toType, fromType))) Then
                                    Return True
                                End If
                                If throwOnError Then
                                    Throw New InvalidOperationException(SR.GetString("Error_MemberWithSameNameExists", New Object() { activityBind.Path, dataSourceClass.FullName }))
                                End If
                                Return False
                            End If
                            Dim activity2 As Activity = Nothing
                            If (String.Compare(component.Name, path, If(ignoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) = 0) Then
                                activity2 = component
                            ElseIf (TypeOf component Is CompositeActivity AndAlso TypeOf component Is CompositeActivity) Then
                                Dim activity3 As Activity
                                For Each activity3 In Helpers.GetAllNestedActivities([TryCast](component,CompositeActivity))
                                    If (String.Compare(activity3.Name, path, If(ignoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) = 0) Then
                                        activity2 = activity3
                                    End If
                                Next
                            End If
                            If (Not activity2 Is Nothing) Then
                                If TypeProvider.IsAssignable(toType, activity2.GetType) Then
                                    Return True
                                End If
                                If throwOnError Then
                                    Throw New InvalidOperationException(SR.GetString("Error_MemberWithSameNameExists", New Object() { activityBind.Path, dataSourceClass.FullName }))
                                End If
                                Return False
                            End If
                            Dim service As IMemberCreationService = [TryCast](context.GetService(GetType(IMemberCreationService)),IMemberCreationService)
                            If (Not service Is Nothing) Then
                                Dim host As IDesignerHost = [TryCast](context.GetService(GetType(IDesignerHost)),IDesignerHost)
                                If (Not host Is Nothing) Then
                                    service.CreateField(host.RootComponentClassName, activityBind.Path, toType, Nothing, MemberAttributes.Public, Nothing, False)
                                    Return True
                                End If
                                If throwOnError Then
                                    Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IDesignerHost).FullName }))
                                End If
                            ElseIf throwOnError Then
                                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IMemberCreationService).FullName }))
                            End If
                        End If
                    End If
                Else
                    If ((component Is Nothing) AndAlso throwOnError) Then
                        Throw New InvalidOperationException(SR.GetString("Error_InvalidActivityIdentifier", New Object() { activityBind.Name }))
                    End If
                    If ((toType Is Nothing) AndAlso throwOnError) Then
                        Throw New InvalidOperationException(SR.GetString("Error_PropertyTypeNotDefined", New Object() { context.PropertyDescriptor.Name, GetType(ActivityBind).Name, GetType(IDynamicPropertyTypeProvider).Name }))
                    End If
                End If
            End If
            Return False
        End Function

        Friend Shared Function FindMatchingMember(ByVal name As String, ByVal ownerType As Type, ByVal ignoreCase As Boolean) As MemberInfo
            Dim info2 As MemberInfo
            For Each info2 In ownerType.GetMembers((BindingFlags.FlattenHierarchy Or (BindingFlags.NonPublic Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))))
                If info2.Name.Equals(name, If(ignoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) Then
                    Return info2
                End If
            Next
            Return Nothing
        End Function

        Friend Shared Function GetBindableMembers(ByVal obj As Object, ByVal context As ITypeDescriptorContext) As IList([Of] MemberInfo)
            Dim list As New List([Of] MemberInfo)
            Dim service As IDesignerHost = [TryCast](context.GetService(GetType(IDesignerHost)),IDesignerHost)
            Dim activity As Activity = If((Not service Is Nothing), [TryCast](service.RootComponent,Activity), Nothing)
            Dim type As Type = If((obj Is activity), Helpers.GetDataSourceClass(activity, context), obj.GetType)
            Dim toType As Type = PropertyDescriptorUtils.GetBaseType(context.PropertyDescriptor, context.Instance, context)
            If ((Not type Is Nothing) AndAlso (Not toType Is Nothing)) Then
                Dim property As DependencyProperty = DependencyProperty.FromName(context.PropertyDescriptor.Name, context.PropertyDescriptor.ComponentType)
                Dim flag As Boolean = ((Not [property] Is Nothing) AndAlso [property].IsEvent)
                Dim bindingAttr As BindingFlags = (BindingFlags.FlattenHierarchy Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))
                If (obj Is activity) Then
                    bindingAttr = (bindingAttr Or BindingFlags.NonPublic)
                End If
                Dim info As MemberInfo
                For Each info In type.GetMembers(bindingAttr)
                    Dim customAttributes As Object() = info.GetCustomAttributes(GetType(DebuggerNonUserCodeAttribute), False)
                    If (((customAttributes Is Nothing) OrElse (customAttributes.Length <= 0)) OrElse Not TypeOf customAttributes(0) Is DebuggerNonUserCodeAttribute) Then
                        Dim objArray2 As Object() = info.GetCustomAttributes(GetType(BrowsableAttribute), False)
                        If (objArray2.Length > 0) Then
                            Dim browsable As Boolean = False
                            Dim attribute As BrowsableAttribute = [TryCast](objArray2(0),BrowsableAttribute)
                            If (Not attribute Is Nothing) Then
                                browsable = attribute.Browsable
                            Else
                                Try 
                                    Dim attribute2 As AttributeInfoAttribute = [TryCast](objArray2(0),AttributeInfoAttribute)
                                    If ((Not attribute2 Is Nothing) AndAlso (attribute2.AttributeInfo.ArgumentValues.Count > 0)) Then
                                        browsable = CBool(attribute2.AttributeInfo.GetArgumentValueAs(context, 0, GetType(Boolean)))
                                    End If
                                Catch obj1 As Object
                                End Try
                            End If
                            If Not browsable Then
                                goto Label_035E
                            End If
                        End If
                        If ((Not info.DeclaringType Is GetType(Object)) OrElse (Not String.Equals(info.Name, "Equals", StringComparison.Ordinal) AndAlso Not String.Equals(info.Name, "ReferenceEquals", StringComparison.Ordinal))) Then
                            Dim flag3 As Boolean = False
                            Dim flag4 As Boolean = False
                            Dim isAssembly As Boolean = False
                            If (flag AndAlso TypeOf info Is EventInfo) Then
                                Dim info2 As EventInfo = [TryCast](info,EventInfo)
                                Dim addMethod As MethodInfo = info2.GetAddMethod
                                Dim removeMethod As MethodInfo = info2.GetRemoveMethod
                                flag4 = (((((Not addMethod Is Nothing) AndAlso addMethod.IsFamily) OrElse ((Not removeMethod Is Nothing) AndAlso removeMethod.IsFamily)) OrElse ((Not addMethod Is Nothing) AndAlso addMethod.IsPublic)) OrElse ((Not removeMethod Is Nothing) AndAlso removeMethod.IsPublic))
                                isAssembly = (((Not addMethod Is Nothing) AndAlso addMethod.IsAssembly) OrElse ((Not removeMethod Is Nothing) AndAlso removeMethod.IsAssembly))
                                flag3 = TypeProvider.IsAssignable(toType, info2.EventHandlerType)
                            ElseIf TypeOf info Is FieldInfo Then
                                Dim info5 As FieldInfo = [TryCast](info,FieldInfo)
                                flag4 = (info5.IsFamily OrElse info5.IsPublic)
                                isAssembly = info5.IsAssembly
                                flag3 = TypeProvider.IsAssignable(toType, info5.FieldType)
                            ElseIf TypeOf info Is PropertyInfo Then
                                Dim info6 As PropertyInfo = [TryCast](info,PropertyInfo)
                                Dim getMethod As MethodInfo = info6.GetGetMethod
                                Dim setMethod As MethodInfo = info6.GetSetMethod
                                flag4 = (((((Not getMethod Is Nothing) AndAlso getMethod.IsFamily) OrElse ((Not setMethod Is Nothing) AndAlso setMethod.IsFamily)) OrElse ((Not getMethod Is Nothing) AndAlso getMethod.IsPublic)) OrElse ((Not setMethod Is Nothing) AndAlso setMethod.IsPublic))
                                isAssembly = (((Not getMethod Is Nothing) AndAlso getMethod.IsAssembly) OrElse ((Not setMethod Is Nothing) AndAlso setMethod.IsAssembly))
                                flag3 = ((Not getMethod Is Nothing) AndAlso TypeProvider.IsAssignable(toType, info6.PropertyType))
                            End If
                            If (((Not info.DeclaringType Is type) AndAlso Not flag4) AndAlso ((Not info.DeclaringType.Assembly Is Nothing) OrElse Not isAssembly)) Then
                                flag3 = False
                            End If
                            If flag3 Then
                                list.Add(info)
                            End If
                        End If
                    Label_035E:
                    End If
                Next
            End If
            Return list.AsReadOnly
        End Function

        Public Overrides Function GetEditor(ByVal editorBaseType As Type) As Object
            Dim editor As Object = MyBase.GetEditor(editorBaseType)
            If ((Not editorBaseType Is GetType(UITypeEditor)) OrElse Me.IsReadOnly) Then
                Return editor
            End If
            Dim obj3 As Object = If((Not Me.PropertyOwner Is Nothing), Me.GetValue(Me.PropertyOwner), Nothing)
            Dim propertiesSupported As Boolean = MyBase.RealPropertyDescriptor.Converter.GetPropertiesSupported(If((Not Me.PropertyOwner Is Nothing), New TypeDescriptorContext(MyBase.ServiceProvider, MyBase.RealPropertyDescriptor, Me.PropertyOwner), Nothing))
            If (Not TypeOf obj3 Is ActivityBind AndAlso ((Not editor Is Nothing) OrElse propertiesSupported)) Then
                Return editor
            End If
            Return New BindUITypeEditor
        End Function

        Public Overrides Function GetValue(ByVal component As Object) As Object
            Dim binding As Object = Nothing
            Dim obj3 As DependencyObject = [TryCast](component,DependencyObject)
            Dim dependencyProperty As DependencyProperty = DependencyProperty.FromName(Me.Name, Me.ComponentType)
            If (((Not obj3 Is Nothing) AndAlso (Not dependencyProperty Is Nothing)) AndAlso obj3.IsBindingSet(dependencyProperty)) Then
                binding = obj3.GetBinding(dependencyProperty)
            End If
            If Not TypeOf binding Is ActivityBind Then
                binding = MyBase.GetValue(component)
            End If
            Return binding
        End Function

        Friend Shared Function IsBindableProperty(ByVal propertyDescriptor As PropertyDescriptor) As Boolean
            If (propertyDescriptor.PropertyType Is GetType(ActivityBind)) Then
                Return True
            End If
            If TypeOf propertyDescriptor.Converter Is ActivityBindTypeConverter Then
                Return True
            End If
            Dim property As DependencyProperty = DependencyProperty.FromName(propertyDescriptor.Name, propertyDescriptor.ComponentType)
            Return ((GetType(DependencyObject).IsAssignableFrom(propertyDescriptor.ComponentType) AndAlso (Not [property] Is Nothing)) AndAlso Not [property].DefaultMetadata.IsMetaProperty)
        End Function

        Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
            Dim obj2 As Object = Me.GetValue(component)
            Dim bind As ActivityBind = [TryCast](value,ActivityBind)
            Dim obj3 As DependencyObject = [TryCast](component,DependencyObject)
            Dim dependencyProperty As DependencyProperty = DependencyProperty.FromName(Me.Name, Me.ComponentType)
            If (((Not obj3 Is Nothing) AndAlso (Not dependencyProperty Is Nothing)) AndAlso (Not bind Is Nothing)) Then
                [Using] New ComponentChangeDispatcher(MyBase.ServiceProvider, obj3, Me)
                    If (dependencyProperty.IsEvent AndAlso (Not MyBase.ServiceProvider Is Nothing)) Then
                        Dim service As IEventBindingService = [TryCast](MyBase.ServiceProvider.GetService(GetType(IEventBindingService)),IEventBindingService)
                        If ((Not service Is Nothing) AndAlso (Not service.GetEvent(MyBase.RealPropertyDescriptor) Is Nothing)) Then
                            MyBase.RealPropertyDescriptor.SetValue(component, Nothing)
                        End If
                    End If
                    obj3.SetBinding(dependencyProperty, bind)
                    MyBase.OnValueChanged(obj3, EventArgs.Empty)
                    goto Label_00F8
                End [Using]
            End If
            If (((Not obj3 Is Nothing) AndAlso (Not dependencyProperty Is Nothing)) AndAlso obj3.IsBindingSet(dependencyProperty)) Then
                [Using] New ComponentChangeDispatcher(MyBase.ServiceProvider, obj3, Me)
                    obj3.RemoveProperty(dependencyProperty)
                    MyBase.OnValueChanged(obj3, EventArgs.Empty)
                End [Using]
            End If
            MyBase.SetValue(component, value)
        Label_00F8:
            If ((Not obj2 Is value) AndAlso ((TypeOf obj2 Is ActivityBind AndAlso Not TypeOf value Is ActivityBind) OrElse (Not TypeOf obj2 Is ActivityBind AndAlso TypeOf value Is ActivityBind))) Then
                TypeDescriptor.Refresh(component)
            End If
        End Sub


        ' Properties
        Public Overrides ReadOnly Property Attributes As AttributeCollection
            Get
                Dim list As New List([Of] Attribute)
                Dim attribute As Attribute
                For Each attribute In MyBase.Attributes
                    list.Add(attribute)
                Next
                Dim editor As Object = MyBase.RealPropertyDescriptor.GetEditor(GetType(UITypeEditor))
                Dim obj3 As Object = If((Not Me.PropertyOwner Is Nothing), Me.GetValue(Me.PropertyOwner), Nothing)
                Dim propertiesSupported As Boolean = MyBase.RealPropertyDescriptor.Converter.GetPropertiesSupported(If((Not Me.PropertyOwner Is Nothing), New TypeDescriptorContext(MyBase.ServiceProvider, MyBase.RealPropertyDescriptor, Me.PropertyOwner), Nothing))
                If ((((editor Is Nothing) AndAlso Not propertiesSupported) OrElse TypeOf obj3 Is ActivityBind) AndAlso Not Me.IsReadOnly) Then
                    list.Add(New EditorAttribute(GetType(BindUITypeEditor), GetType(UITypeEditor)))
                End If
                Return New AttributeCollection(list.ToArray)
            End Get
        End Property

        Public Overrides ReadOnly Property Converter As TypeConverter
            Get
                Dim converter As TypeConverter = MyBase.Converter
                If GetType(ActivityBindTypeConverter).IsAssignableFrom(converter.GetType) Then
                    Return converter
                End If
                Return New ActivityBindTypeConverter
            End Get
        End Property

        Public Overrides ReadOnly Property IsReadOnly As Boolean
            Get
                Return MyBase.RealPropertyDescriptor.IsReadOnly
            End Get
        End Property

        Friend ReadOnly Property PropertyOwner As Object
            Get
                Return Me.propertyOwner
            End Get
        End Property


        ' Fields
        Private propertyOwner As Object
    End Class
End Namespace

